package com.smart.system.domain;

import com.smart.common.exception.ServiceException;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LineSegment;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 道格拉斯普克算法
 */
public class EnhancedTrajectorySimplifier {

    // 动态调整阈值系数
    private static final double DYNAMIC_FACTOR = 0.1;

    /**
     * 增强版抽稀（支持动态阈值、并行、JTS）
     * @param points 轨迹点集合
     * @param targetPoints 目标点数
     * @param parallel 是否启用并行
     */
    public static List<AreaLocation> simplify(List<AreaLocation> points, int targetPoints, boolean parallel) {
        if (points.size() <= targetPoints) return new ArrayList<>(points);

        double minEpsilon = 0.001; // 最小阈值
        double maxEpsilon = 100.0; // 最大阈值
        double epsilon = (minEpsilon + maxEpsilon) / 2.0;
        List<AreaLocation> simplifiedPoints = points;

        int maxIterations = 1000; // 最大迭代次数，防止死循环
        int iteration = 0;

        while (Math.abs(simplifiedPoints.size() - targetPoints) > 1 && iteration < maxIterations) {
            simplifiedPoints = parallel ?
                    parallelSimplify(points, epsilon) :
                    recursiveSimplify(points, epsilon);

            if (simplifiedPoints.size() > targetPoints) {
                minEpsilon = epsilon;
                epsilon = (minEpsilon + maxEpsilon) / 2.0;
            } else {
                maxEpsilon = epsilon;
                epsilon = (minEpsilon + maxEpsilon) / 2.0;
            }

            iteration++;
        }

        // 确保最终点数不超过目标点数
        if (simplifiedPoints.size() > targetPoints) {
            simplifiedPoints = simplifiedPoints.subList(0, targetPoints);
        }

        return simplifiedPoints;
    }

    // 并行处理入口
    private static List<AreaLocation> parallelSimplify(List<AreaLocation> points, double epsilon) {
        ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
        try {
            return pool.submit(() -> recursiveSimplify(points, epsilon)).get();
        } catch (Exception e) {
            throw new ServiceException("并行处理失败!");
        } finally {
            pool.shutdown();
        }
    }

    // 核心递归逻辑（JTS集成）
    private static List<AreaLocation> recursiveSimplify(List<AreaLocation> points, double epsilon) {
        int maxIndex = findMaxDeviationIndex(points);
        double maxDistance = calculateMaxDistance(points, maxIndex);

        if (maxDistance > epsilon) {
            return combineResults(
                    recursiveSimplify(points.subList(0, maxIndex + 1), epsilon),
                    recursiveSimplify(points.subList(maxIndex, points.size()), epsilon)
            );
        } else {
            return Arrays.asList(points.get(0), points.get(points.size() - 1));
        }
    }

    // 使用JTS计算点到线段距离
    private static int findMaxDeviationIndex(List<AreaLocation> points) {
        Coordinate start = convertToCoordinate(points.get(0));
        Coordinate end = convertToCoordinate(points.get(points.size()-1));
        LineSegment segment = new LineSegment(start, end);

        int maxIndex = 0;
        double maxDist = 0;
        for (int i = 1; i < points.size()-1; i++) {
            double dist = segment.distance(convertToCoordinate(points.get(i)));
            if (dist > maxDist) {
                maxDist = dist;
                maxIndex = i;
            }
        }
        return maxIndex;
    }

    // 辅助方法
    private static Coordinate convertToCoordinate(AreaLocation point) {
        return new Coordinate(
                parseDouble(point.getLongitude()),
                parseDouble(point.getLatitude())
        );
    }

    private static double calculateMaxDistance(List<AreaLocation> points, int index) {
        Coordinate start = convertToCoordinate(points.get(0));
        Coordinate end = convertToCoordinate(points.get(points.size()-1));
        return new LineSegment(start, end).distance(convertToCoordinate(points.get(index)));
    }

    private static List<AreaLocation> combineResults(List<AreaLocation> left, List<AreaLocation> right) {
        return Stream.concat(
                left.subList(0, left.size()-1).stream(),
                right.stream()
        ).collect(Collectors.toList());
    }

    // 保留原有安全转换方法
    private static double parseDouble(String value) {
        try {
            return Double.parseDouble(value);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid coordinate: " + value);
        }
    }

    /**
     * 将多个 EmployeeTrajectory 对象合并为轨迹并抽稀
     * @param trajectories 需要抽稀的轨迹对象列表（按时间顺序排列）
     * @param targetPoints 目标点数
     * @param parallel 是否启用并行处理
     */
    public static List<EmployeeTrajectory> simplifyTrajectories(
            List<EmployeeTrajectory> trajectories,
            int targetPoints,
            boolean parallel
    ) {
        // 提取原始轨迹点列表（假设每个轨迹对象对应一个点）
        List<AreaLocation> points = trajectories.stream()
                .map(EmployeeTrajectory::getAreaLocation)
                .collect(Collectors.toList());

        if (points.size() <= targetPoints) {
            return trajectories; // 直接返回原始轨迹列表
        }

        // 转换为 Coordinate 列表并抽稀
        List<Coordinate> coordinates = convertToCoordinates(points);
        List<Coordinate> simplifiedCoordinates = recursiveSimplify(coordinates, targetPoints, parallel); // 假设核心抽稀逻辑在此

        // 转换回 AreaLocation 列表
        List<AreaLocation> simplifiedPoints = convertToAreaLocations(simplifiedCoordinates);

        // 生成新的 EmployeeTrajectory 列表
        List<EmployeeTrajectory> result = new ArrayList<>();

        // 假设抽稀后的点顺序与原始轨迹一致，按索引对应
        for (int i = 0; i < simplifiedPoints.size(); i++) {
            EmployeeTrajectory original = trajectories.get(i);
            EmployeeTrajectory simplifiedTrajectory = new EmployeeTrajectory();
            // 复制必要字段（如 userId、createTime、deptId 等）
            simplifiedTrajectory.setUserId(original.getUserId());
            simplifiedTrajectory.setDeptId(original.getDeptId());
            simplifiedTrajectory.setCreateTime(original.getCreateTime()); // 假设存在时间字段
            simplifiedTrajectory.setAreaLocation(simplifiedPoints.get(i));
            result.add(simplifiedTrajectory);
        }

        return result;
    }

    // 假设核心抽稀逻辑在此（示例）
    private static List<Coordinate> recursiveSimplify(
            List<Coordinate> points,
            int targetPoints,
            boolean parallel
    ) {
        // 这里调用实际的抽稀算法（如 Douglas-Peucker）
        List<AreaLocation> simplify = simplify(convertToAreaLocations(points), targetPoints, parallel);
        // 示例返回原列表，需替换为真实逻辑
        return convertToCoordinates(simplify);
    }



    // 将 AreaLocation 列表转换为 Coordinate 列表
    public static List<Coordinate> convertToCoordinates(List<AreaLocation> points) {
        return points.stream()
                .map(p -> new Coordinate(
                        Double.parseDouble(p.getLongitude()),
                        Double.parseDouble(p.getLatitude())
                ))
                .collect(Collectors.toList());
    }

    // 将 Coordinate 列表转换为 AreaLocation 列表
    public static List<AreaLocation> convertToAreaLocations(List<Coordinate> coordinates) {
        return coordinates.stream()
                .map(c -> new AreaLocation(
                        null,
                        String.valueOf(c.x),
                        String.valueOf(c.y),
                        null
                ))
                .collect(Collectors.toList());
    }

}
